home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / ab20 / ab20_archive / datacomm / xpr / xprkermit-1.111.lzh / xprkermit.c < prev    next >
C/C++ Source or Header  |  1991-11-27  |  25KB  |  934 lines

  1. /** xprkermit.c
  2. *
  3. *   $Log:    xprkermit.c,v $
  4.  * Revision 1.3  91/11/09  06:53:22  swalton
  5.  * Added support for re-entrant library, by cloning the data segment on entrance
  6.  * to the protocol.  This is something of a trick which depends heavily on
  7.  * the particular way Aztec C organizes small model segments, but it seems
  8.  * to work fine.
  9.  * 
  10. *
  11. *   These are the protocol transfer routines for a simple Kermit upload/dnload
  12. *
  13. *   Version 0.9--by Marco Papa.
  14. *
  15. *   Version 1.0--updated by Stephen Walton.
  16. *    Added several more user selections to XPRotocolSetup():
  17. *    bctr (block check type to request), limit (retry-limit), and
  18. *    rtimo (timeout for me).  "Real" C Kermit makes many of the
  19. *    things declared as local to kermitproto.w user-settable,
  20. *    such as the send packet size.
  21. *    Also fixed several problems in kermitproto.w.
  22. *
  23. *   Version 1.5--more features
  24. *    Extensive changes.
  25. *    (1) Created a SetupVars variable to hold setting-up information
  26. *    in the XPR_IO structure.  This will allow re-entrancy when and if
  27. *    it comes.  Right now, it mainly gives a way to set up defaults with
  28. *    one assignment.
  29. *    (2) Added the generic Kermit server functions FINISH, BYE, and CD.
  30. *    (3) Added the ability to set options and execute the server functions
  31. *    from a setup string (sent as IO->xpr_filename to XPRotocolSetup()).
  32. *
  33. *   Version 1.6
  34. *    Some changes to the chkint() code in kermitproto.w to allow better
  35. *    file cancellations.  In particular, -1 is returned if the user
  36. *    does the maximum XPR abort.
  37. *
  38. *    Bug fixed in malloc() in this module:  it wasn't saving the correct
  39. *    number of allocated characters.
  40. *
  41. *   Version 1.61
  42. *    More mucking with chkint().  Irrelevant to VLT at present.
  43. *
  44. *   Version 1.62
  45. *    "Final" version of interrupt code.  Based on C Kermit, if chkint()
  46. *    returns a negative number, I both put "User cancelled."  on the
  47. *    display and send it in an error packet to the other end.
  48. *
  49. *   Version 1.63
  50. *    gnchar() in kermitproto.w wasn't counting nulls!  Fixed.
  51. *
  52. *    This code is copyright 1990 by Stephen Walton and Marco Papa.  It may
  53. *    be freely distributed in its original or in modified form, provided
  54. *    this copyright notice is kept intact.  It may not be sold for profit,
  55. *    but may be included as part of a commercial program provided that
  56. *    said inclusion does not increase the cost of that program beyond a
  57. *    modest handling fee.
  58. **/
  59.  
  60. #ifndef _lint
  61. static char rcsid[] = "$Header: Work:src/xprkermit/RCS/xprkermit.c,v 1.3 91/11/09 06:53:22 swalton Exp Locker: swalton $";
  62. #endif
  63.  
  64. #include <exec/memory.h>
  65. #include <functions.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69.  
  70. /*
  71.  * xproto.h is the include file given in Appendix B.  It is included
  72.  * in xprkermit.h
  73.  */
  74.  
  75. #include "xprkermit.h"
  76. #include "kermitproto.h"
  77. #include "timer.h"
  78. #include "version.h"
  79.  
  80. long            (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (), (*xfread) (),
  81.                 (*xsread) (), (*xchkabort) (), (*xfnext) (), (*xffirst) (), (*xsflush) (),
  82.                 (*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
  83.         (*xsquery) (), (*xchkmisc) ();
  84.  
  85. extern CHAR     start;        /* The start state for the protocol. */
  86.  
  87. /*
  88.  * Forward declarations
  89.  */
  90. static SetupVars *setup(struct XPR_IO *IO);
  91.  
  92. /*
  93.  * The flags for the kermitproto.w module.
  94.  */
  95. char           *p_pattern;    /* wildcard pattern */
  96. int             parity;        /* parity on? 0 for no parity--need for
  97.                  * proper 8th-bit quote */
  98. int             text;        /* Text or binary mode? Flag 1 for text file,
  99.                  * 0 for binary file     */
  100. int             convert;    /* Convert file names to lower case? 0 for
  101.                  * literal files (no), 1 for translate (yes) */
  102. int             urpsiz;        /* Kermit maximum packet size. Maximum
  103.                  * receive packet size user wants.     */
  104. char           *cmarg;        /* Character string containing Kermit server
  105.                  * cmd */
  106.  
  107. extern int      bctr;        /* Block check type to request. */
  108. extern int      limit;        /* Retry limit.  May increase on very noisy
  109.                  * lines. */
  110. extern int      rtimo;        /* Timeout to request. */
  111. extern int    keep;        /* Keep incomplete files? */
  112.  
  113. int             getfile;    /* Host server. 0 = Receive (no) ; 1 = Get
  114.                  * (yes) */
  115. long            brkflag;
  116.  
  117. static SetupVars Defaults = {
  118.     0L,                /* Data segment--to be filled in later */
  119.     {""},            /* No default file name. */
  120.     0,                /* Parity defaults to off. */
  121.     1,                /* Text file defaults to on. */
  122.     1,                /* Convert file names by default. */
  123.     94,                /* Default maximum packet length. */
  124.     1,                /* Default block check type. */
  125.     5,                /* Retry limit */
  126.     10,                /* Timeout (seconds) */
  127.     0,                /* Don't keep incomplete files */
  128.     0,                /* Host is server?  No by default. */
  129. };
  130.  
  131. /*
  132.  * Local prototypes.
  133.  */
  134. static KermitCd(struct XPR_IO *IO, char *dir);
  135. static KermitFinish(struct XPR_IO *IO);
  136. static KermitBye(struct XPR_IO *IO);
  137. static DoGeneric(struct XPR_IO *IO, char *s);
  138.  
  139.  
  140. /**
  141. *
  142. *   Send a file
  143. *
  144. **/
  145. long
  146. XProtocolSend(IO)
  147.     struct XPR_IO  *IO;
  148. {
  149.     struct XPR_UPDATE xpru;
  150.     SetupVars      *sv;
  151.  
  152.     if ((sv = setup(IO)) == NULL)
  153.     return 0L;        /* Initialize parameters. */
  154.  
  155.     brkflag = 0;
  156.  
  157.     /*
  158.      * Read the text/binary set using xpr_finfo if present.  Else use the
  159.      * value chosen in XPRotocolSetup.
  160.      */
  161.     if (xfinfo) {
  162.     /*
  163.      * Use feature that calling xpr_finfo with a zero-length filename
  164.      * returns setting of internal comm program Text/Binary flag.
  165.      */
  166.     text = (callad(xfinfo, IO->xpr_filename, 2L) == 1 ? 0 : 1);
  167.     }
  168.     /*
  169.      * Start the transfer. See 3.8 for a discussion on how to implement
  170.      * xupdate.
  171.      */
  172.     tchar('#');
  173.  
  174.     /*
  175.      * Copy filename, and put pointer in external Kermit variable.
  176.      */
  177.     strcpy(sv->FileName, IO->xpr_filename);
  178.     p_pattern = sv->FileName;
  179.     /*
  180.      * */
  181.     start = 's';
  182.     proto();
  183.  
  184.     /*
  185.      * If we got here through chkabort() say Aborted.
  186.      */
  187.     xpru.xpru_updatemask = XPRU_MSG;
  188.     if (brkflag)
  189.     xpru.xpru_msg = "Aborted";
  190.     else
  191.     xpru.xpru_msg = "Done";
  192.     (void) calla(xupdate, &xpru);
  193.     if (brkflag)
  194.     return (0L);
  195.     else
  196.     return (1L);
  197. }
  198.  
  199.  
  200. /**
  201. *
  202. *   Receive a file.
  203. *
  204. **/
  205. long
  206. XProtocolReceive(IO)
  207.     struct XPR_IO  *IO;
  208. {
  209.     struct XPR_UPDATE xpru;
  210.     long            status;
  211.     SetupVars      *sv;
  212.  
  213.     if ((sv = setup(IO)) == NULL)
  214.     return 0L;            /* Initialize parameters. */
  215.  
  216.     brkflag = 0;
  217.  
  218.     /*
  219.      * Read the text/binary set using xpr_finfo if present.  Else use the
  220.      * value chosen in XPRotocolSetup.
  221.      */
  222.     if (xfinfo) {
  223.     /*
  224.      * Use feature th at calling xpr_finfo with a zero-length filename
  225.      * returns setting of internal comm program Text/Binary flag.
  226.      */
  227.     text = (callad(xfinfo, "", 2L) == 1 ? 0 : 1);
  228.     }
  229.     /*
  230.      * Start the transfer. See 3.8 for a discussion on how to implement
  231.      * xupdate.
  232.      */
  233.     tchar('#');
  234.  
  235.     if (getfile) {
  236.     /*
  237.      * Copy filename, and put pointer in external Kermit variable.
  238.      */
  239.     cmarg = sv->FileName;
  240.     start = 'r';
  241.     status = callaa(xgets, "Host Filename", cmarg);
  242.     if (!status)
  243.         return (0L);
  244.     } else
  245.     start = 'v';
  246.     proto();
  247.  
  248.     /*
  249.      * If we got here through chkabort() say Aborted.
  250.      */
  251.     xpru.xpru_updatemask = XPRU_MSG;
  252.     if (brkflag)
  253.     xpru.xpru_msg = "Aborted";
  254.     else
  255.     xpru.xpru_msg = "Done";
  256.     (void) calla(xupdate, &xpru);
  257.     if (brkflag)
  258.     return (0L);
  259.     else
  260.     return (1L);
  261. }
  262.  
  263. /*
  264.  * Perform a generic Kermit server command.
  265.  */
  266. static
  267. DoGeneric(IO, s)
  268.     struct XPR_IO  *IO;
  269.     char           *s;
  270. {
  271.     if (setup(IO) == NULL)
  272.     return 0;            /* Set up transfer characteristics. */
  273.     brkflag = 0;
  274.     start = 'g';
  275.     cmarg = s;
  276.     proto();
  277.     if (brkflag)
  278.     return (0);
  279.     else
  280.     return (1);
  281. }
  282.  
  283. /*
  284.  * Execute a Kermit FINISH command.
  285.  */
  286. static
  287. KermitFinish(IO)
  288.     struct XPR_IO  *IO;
  289. {
  290.     return (DoGeneric(IO, "F"));
  291. }
  292.  
  293. /*
  294.  * Execute a Kermit BYE command.
  295.  */
  296. static
  297. KermitBye(IO)
  298.     struct XPR_IO  *IO;
  299. {
  300.     return (DoGeneric(IO, "L"));
  301. }
  302.  
  303. /*
  304.  * Change directory on remote server.  We need to return an error if the CD
  305.  * fails on the remote end.
  306.  */
  307. static
  308. KermitCd(IO, dir)
  309.     struct XPR_IO  *IO;
  310.     char           *dir;
  311. {
  312.     char            CdCommand[100];
  313.     int             retval;
  314.  
  315.     CdCommand[0] = 'C';
  316.     CdCommand[1] = (char) tochar(strlen(dir));
  317.     strcpy(CdCommand + 2, dir);
  318.     retval = DoGeneric(IO, CdCommand);
  319.     return retval;
  320. }
  321.  
  322. /**
  323. *
  324. *   Setup
  325. *
  326. * First, a general-purpose comparison for either of the two possible returns
  327. * indicating a Yes push on a Boolean gadget.
  328. **/
  329.  
  330. #define XprBoolTrue(s) ((stricmp(s, "yes") == 0) || (stricmp(s, "on") == 0))
  331.  
  332. /*
  333.  * Then, a small set of code to initialize a string based on a value.
  334.  */
  335.  
  336. #define XprSet(value, string) ((value) ? \
  337.    (void) strcpy(string, YesString) : \
  338.    (void) strcpy(string, NoString)) \
  339.  
  340. static char     YesString[] = "yes";
  341. static char     NoString[] = "no";
  342.  
  343. /*
  344.  * If Setup() succeeds, flag same.  Also, we don't need a file requester
  345.  * on receive.
  346.  */
  347. #define SUCCESS (XPRS_SUCCESS | XPRS_NORECREQ)
  348.  
  349. extern char _H1_org, _H1_end, _H2_org, _H2_end;        /* Data segment pointers */
  350. static void NewDataSeg(void *);
  351.  
  352. #pragma regcall(NewDataSeg(a0))
  353.  
  354. static SetupVars *
  355. InitData(struct XPR_IO *IO) {
  356.     SetupVars *sv;
  357.  
  358.     /*
  359.      * Allocate memory for file name buffer and options if first call.  Also
  360.      * allocate user's data segment and point us at it.
  361.      */
  362.     if ((sv = IO->xpr_data) == NULL) {
  363.     if ((sv = (SetupVars *) malloc(sizeof(SetupVars))) == NULL)
  364.         return NULL;
  365.     *sv = Defaults;
  366.     if ((sv->DataSeg = malloc(&_H2_end - &_H1_org + 4)) == NULL) {
  367.         free(sv);
  368.         return NULL;
  369.     }
  370.     memcpy(sv->DataSeg, &_H1_org, &_H2_end - &_H1_org + 4);
  371.     IO->xpr_data = sv;
  372.     }
  373.     NewDataSeg(sv->DataSeg);
  374.     return(sv);
  375. }
  376.  
  377. long
  378. XProtocolSetup(IO)
  379.     struct XPR_IO  *IO;
  380. {
  381.     long            (*xoptions) ();
  382. #define NOPTS 10
  383.     struct xpr_option opt[NOPTS], *popt[NOPTS];
  384. #define MAXSTRING 6
  385.     char            ValueStrings[NOPTS][MAXSTRING];
  386.     long            status;
  387.     int             i, j;
  388.     char            buf[256];
  389.     SetupVars      *sv, tempvar;
  390.  
  391.     if ((sv = InitData(IO)) == NULL)
  392.         return (XPRS_FAILURE);
  393.  
  394.     if ((xupdate = IO->xpr_update) == NULL)
  395.     return (XPRS_FAILURE);
  396.     if ((xgets = IO->xpr_gets) == NULL)
  397.     return (XPRS_FAILURE);
  398.  
  399.     tempvar = *sv;
  400.     /*
  401.      * In order to use xpr_options, we must have all of the three conditions
  402.      * which follow true.  Otherwise, either IO->xpr_filename is non-NULL, in
  403.      * which case we assume it contains a setup string, or there is no
  404.      * xpr_options, in which case we use xpr_gets to retrieve a setup string.
  405.      */
  406.     if (IO->xpr_filename == NULL &&
  407.     IO->xpr_extension >= 1 &&
  408.     (xoptions = IO->xpr_options) != NULL) {
  409.  
  410.     /*
  411.      * I use a counter, i, here, so that I can stick in more options
  412.      * without needing to change a lot of numbers.  I can also skip
  413.      * options dynamically, as in Text below.
  414.      */
  415.     i = 0;
  416.     /* Announce us. */
  417.     opt[i].xpro_description = "Kermit Commands " VSTRING;
  418.     opt[i].xpro_type = XPRO_HEADER;
  419.     opt[i].xpro_value = NULL;
  420.     opt[i].xpro_length = 0;
  421.     i++;
  422.     /*
  423.      * First, do the Kermit server command items.
  424.      */
  425.     opt[i].xpro_description = "Kermit FINISH";
  426.     opt[i].xpro_type = XPRO_COMMAND;
  427.     opt[i].xpro_value = NULL;
  428.     opt[i].xpro_length = 0;
  429.     i++;
  430.     opt[i].xpro_description = "Kermit BYE";
  431.     opt[i].xpro_type = XPRO_COMMAND;
  432.     opt[i].xpro_value = NULL;
  433.     opt[i].xpro_length = 0;
  434.     i++;
  435.     opt[i].xpro_description = "Kermit CD";
  436.     opt[i].xpro_type = XPRO_COMMPAR;
  437.     buf[0] = '\0';
  438.     opt[i].xpro_value = buf;        /* Use buf to hold dir name. */
  439.     opt[i].xpro_length = sizeof(buf) - 1;
  440.     i++;
  441.     opt[i].xpro_description = "Kermit Options";
  442.     opt[i].xpro_type = XPRO_COMMAND;
  443.     opt[i].xpro_value = NULL;
  444.     opt[i].xpro_length = 0;
  445.     i++;
  446.     /* show requester after loading pointers */
  447.     for (j = 0; j < i; j++)
  448.         popt[j] = &opt[j];
  449.     status = callda(xoptions, (long) i, popt);
  450.     /* check returned value */
  451.     if (status == -1L)
  452.         return XPRS_FAILURE;
  453.     /* Check returned value to see what we are to do. */
  454.     i = 1;
  455.     if (status & (1L << i))
  456.         return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
  457.     i++;
  458.     if (status & (1L << i))
  459.         return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
  460.     i++;
  461.     if (status & (1L << i))
  462.         return (KermitCd(IO, opt[i].xpro_value) ? SUCCESS : XPRS_FAILURE);
  463.     /* If we get to this point, we are to set options. */
  464.     i = 0;            /* Start over. */
  465.     opt[i].xpro_description = "Kermit Options " VSTRING;
  466.     opt[i].xpro_type = XPRO_HEADER;
  467.     opt[i].xpro_value = NULL;
  468.     opt[i].xpro_length = 0;
  469.     i++;
  470.     /* Convert filename */
  471.     opt[i].xpro_description = "Convert Filename";
  472.     opt[i].xpro_type = XPRO_BOOLEAN;
  473.     XprSet(tempvar.ConvertFlag, ValueStrings[i]);
  474.     opt[i].xpro_value = ValueStrings[i];
  475.     opt[i].xpro_length = MAXSTRING;
  476.     i++;
  477.     /* Partial file keep */
  478.     opt[i].xpro_description = "Keep Incomplete";
  479.     opt[i].xpro_type = XPRO_BOOLEAN;
  480.     XprSet(tempvar.KeepFlag, ValueStrings[i]);
  481.     opt[i].xpro_value = ValueStrings[i];
  482.     opt[i].xpro_length = MAXSTRING;
  483.     i++;
  484.     /* host is server */
  485.     opt[i].xpro_description = "Host Server";
  486.     opt[i].xpro_type = XPRO_BOOLEAN;
  487.     XprSet(tempvar.GetFlag, ValueStrings[i]);
  488.     opt[i].xpro_value = ValueStrings[i];
  489.     opt[i].xpro_length = MAXSTRING;
  490.     i++;
  491.     /*
  492.      * file type -- only show this if xpr_finfo not present, or returns
  493.      * error when we try to get the file type.
  494.      */
  495.     if ((xfinfo = IO->xpr_finfo) == NULL ||
  496.         (tempvar.TextFlag = (int) (callad(xfinfo, "", 2L))) == 0) {
  497.         tempvar.TextFlag = -1;    /* Flag xfinfo failed. */
  498.         opt[i].xpro_description = "Text File";
  499.         opt[i].xpro_type = XPRO_BOOLEAN;
  500.         XprSet(tempvar.TextFlag, ValueStrings[i]);
  501.         opt[i].xpro_value = ValueStrings[i];
  502.         opt[i].xpro_length = MAXSTRING;
  503.         i++;
  504.     } else
  505.         /*
  506.          * Switch to 0 for binary, 1 for text; xpr_finfo returns 1 for
  507.          * binary, 2 for text.
  508.          */
  509.         tempvar.TextFlag -= 1;
  510.     /* Packet size */
  511.     opt[i].xpro_description = "Packet Size";
  512.     opt[i].xpro_type = XPRO_LONG;
  513.     (void) sprintf(ValueStrings[i], "%-d", tempvar.MaxPacket);
  514.     opt[i].xpro_value = ValueStrings[i];
  515.     opt[i].xpro_length = MAXSTRING;
  516.     i++;
  517.     /* Block Check type */
  518.     opt[i].xpro_description = "Block Check (1, 2, 3)";
  519.     opt[i].xpro_type = XPRO_LONG;
  520.     (void) sprintf(ValueStrings[i], "%-d", tempvar.BlockCheckType);
  521.     opt[i].xpro_value = ValueStrings[i];
  522.     opt[i].xpro_length = MAXSTRING;
  523.     i++;
  524.     /* Retry Limit */
  525.     opt[i].xpro_description = "Maximum Retries";
  526.     opt[i].xpro_type = XPRO_LONG;
  527.     (void) sprintf(ValueStrings[i], "%-d", tempvar.RetryLimit);
  528.     opt[i].xpro_value = ValueStrings[i];
  529.     opt[i].xpro_length = MAXSTRING;
  530.     i++;
  531.     /* Timeout */
  532.     opt[i].xpro_description = "Timeout (seconds)";
  533.     opt[i].xpro_type = XPRO_LONG;
  534.     (void) sprintf(ValueStrings[i], "%-d", tempvar.Timeout);
  535.     opt[i].xpro_value = ValueStrings[i];
  536.     opt[i].xpro_length = MAXSTRING;
  537.     i++;
  538.     /* show requester after loading pointers */
  539.     for (j = 0; j < i; j++)
  540.         popt[j] = &opt[j];
  541.     /* show requester */
  542.     status = callda(xoptions, (long) i, popt);
  543.     /* check returned value */
  544.     if (status == -1L)
  545.         return XPRS_FAILURE;
  546.     i = 1;            /* Skip header         */
  547.     if (status & (1L << i))
  548.         tempvar.ConvertFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  549.     i++;
  550.     if (status & (1L << i))
  551.         tempvar.KeepFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  552.     i++;
  553.     if (status & (1L << i))
  554.         tempvar.GetFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  555.     i++;
  556.     if (xfinfo == NULL || tempvar.TextFlag == -1) {
  557.         if (status & (1L << i))
  558.         tempvar.TextFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
  559.         i++;
  560.     }
  561.     if (status & (1L << i))
  562.         tempvar.MaxPacket = atoi(opt[i].xpro_value);
  563.     i++;
  564.     if (status & (1L << i))
  565.         tempvar.BlockCheckType = atoi(opt[i].xpro_value);
  566.     i++;
  567.     if (status & (1L << i))
  568.         tempvar.RetryLimit = atoi(opt[i].xpro_value);
  569.     i++;
  570.     if (status & (1L << i))
  571.         tempvar.Timeout = atoi(opt[i].xpro_value);
  572.     } else {
  573.     if (IO->xpr_filename != NULL)
  574.         strcpy(buf, IO->xpr_filename);    /* Save setup string */
  575.     else {            /* Prompt for command/options string */
  576.         sprintf(buf, "OC%c,G%c,K%c,T%c,P%d,B%d,R%d,O%d",
  577.                     tempvar.ConvertFlag ? 'Y' : 'N',
  578.             tempvar.GetFlag ? 'Y' : 'N', tempvar.KeepFlag ? 'Y' : 'N',
  579.                     tempvar.TextFlag ? 'Y' : 'N', tempvar.MaxPacket,
  580.            tempvar.BlockCheckType, tempvar.RetryLimit, tempvar.Timeout);
  581.         if (callaa(xgets, "Kermit Options", buf) == 0)
  582.         return XPRS_FAILURE;    /* Failed to set up? */
  583.     }
  584.     (void) strupr(buf);
  585.     switch (buf[0]) {
  586.     case 'F':
  587.         return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
  588.     case 'B':
  589.         return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
  590.     case 'C':
  591.         return (KermitCd(IO, buf + 1) ? SUCCESS : XPRS_FAILURE);
  592.     case 'O':
  593.         if (SetupFromString(IO, buf, &tempvar) == 0)
  594.         return XPRS_FAILURE;
  595.         break;
  596.     case '\0':
  597.         break;
  598.     default:
  599.         ioerr(IO, "Unrecognized XPR Kermit setup string");
  600.         break;
  601.     }
  602.     }
  603.     *sv = tempvar;        /* Copy setups into safe place. */
  604.     /*
  605.      * Return success and inform caller that we don't need a requester for
  606.      * receive.
  607.      */
  608.     return SUCCESS;
  609. }
  610.  
  611. static char Delimiters[] = " \t\r\n,";
  612.  
  613. int
  614. SetupFromString(IO, s, sv)
  615.     struct XPR_IO  *IO;
  616.     char           *s;
  617.     SetupVars      *sv;
  618. {
  619.     char           *p;
  620.     char            errbuf[50];
  621.  
  622.     if (*s != 'O')
  623.     return 0;        /* Options string must start with O. */
  624.     s++;            /* Skip leading O. */
  625.     /*
  626.      * Hunt for options with strtok.  We allow whitespace and commas to
  627.      * separate options.
  628.      */
  629.     for (p = strtok(s, Delimiters); p != NULL; p = strtok(NULL, Delimiters)) {
  630.     switch (*p++) {                /* Auto-increment to option */
  631.     case 'C':                /* Case conversion. */
  632.         if (*p == 'Y' || *p == 'N')
  633.         sv->ConvertFlag = (*p == 'Y');
  634.         else
  635.         ioerr(IO, "Illegal C option format (must be Y or N)");
  636.         break;
  637.     case 'G':                /* Get files (Host server) */
  638.         if (*p == 'Y' || *p == 'N')
  639.         sv->GetFlag = (*p == 'Y');
  640.         else
  641.         ioerr(IO, "Illegal G option format (must be Y or N)");
  642.         break;
  643.     case 'K':                /* Keep incomplete file */
  644.         if (*p == 'Y' || *p == 'N')
  645.         sv->KeepFlag = (*p == 'Y');
  646.         else
  647.         ioerr(IO, "Illegal K option format (must be Y or N)");
  648.         break;
  649.     case 'T':                /* Text file */
  650.         if (*p == 'Y' || *p == 'N')
  651.         sv->TextFlag = (*p == 'Y');
  652.         else
  653.         ioerr(IO, "Illegal T option format (must be Y or N)");
  654.         break;
  655.     case 'P':                /* Maximum packet length */
  656.         sv->MaxPacket = atoi(p);
  657.         break;
  658.     case 'B':                /* Block check type. */
  659.         sv->BlockCheckType = atoi(p);
  660.         break;
  661.     case 'R':                /* Retry limit */
  662.         sv->RetryLimit = atoi(p);
  663.         break;
  664.     case 'O':                /* Timeout */
  665.         sv->Timeout = atoi(p);
  666.         break;
  667.     default:
  668.         sprintf(errbuf, "Illegal XPR Kermit option: %c", p[-1]);
  669.         ioerr(IO, errbuf);
  670.         break;
  671.     }
  672.     }
  673.     return 1;
  674. }
  675.  
  676. /**
  677. *
  678. *   Cleanup
  679. *
  680. **/
  681. long
  682. XProtocolCleanup(IO)
  683.     struct XPR_IO  *IO;
  684. {
  685.     if (((SetupVars *)IO->xpr_data)->DataSeg)
  686.         free(((SetupVars *)IO->xpr_data)->DataSeg);
  687.     if (IO->xpr_data)
  688.     free(IO->xpr_data);
  689.     IO->xpr_data = NULL;
  690.  
  691.     return (1L);
  692. }
  693.  
  694. int
  695. XPRParity(IO)
  696.     struct XPR_IO  *IO;
  697. {
  698.     long            (*xsetserial) ();
  699.     long            status;
  700.  
  701.     /* check out parity */
  702.     if ((xsetserial = IO->xpr_setserial) != NULL) {
  703.     status = calld(xsetserial, -1L);
  704.     if (status & 0x00000001L)
  705.         return 1;
  706.     else
  707.         return 0;
  708.     } else
  709.     return 0;        /* Assume no parity if can't tell. */
  710. }
  711.  
  712. void
  713. XPRLong(IO, i)
  714.     struct XPR_IO  *IO;
  715.     long            i;
  716. {
  717.     struct XPR_UPDATE xpru;
  718.     char            locbuf[80];
  719.  
  720.     if ((xupdate = IO->xpr_update) == NULL)
  721.     return;
  722.     /* debug: show long value */
  723.     xpru.xpru_updatemask = XPRU_MSG;
  724.     sprintf(locbuf, "%lx", i);
  725.     xpru.xpru_msg = &locbuf[0];
  726.     (void) calla(xupdate, &xpru);
  727. }
  728.  
  729. /*
  730.  * Copy setup variables into the local copies.  If there are none, then
  731.  * simply copy the defaults.
  732.  */
  733. static SetupVars *
  734. setup(IO)
  735.     struct XPR_IO  *IO;
  736. {
  737.     register SetupVars *Current;
  738.  
  739.     if ((Current = InitData(IO)) == NULL)
  740.         return NULL;
  741.     /*
  742.      * These are the call-backs we need. If any of them isn't provided, quit.
  743.      * Could do some error reporting if at least xupdate is there.
  744.      */
  745.     if ((xupdate = IO->xpr_update) == NULL)
  746.     return (0L);
  747.     if ((xswrite = IO->xpr_swrite) == NULL)
  748.     return (0L);
  749.     if ((xfopen = IO->xpr_fopen) == NULL)
  750.     return (0L);
  751.     if ((xfclose = IO->xpr_fclose) == NULL)
  752.     return (0L);
  753.     if ((xfread = IO->xpr_fread) == NULL)
  754.     return (0L);
  755.     if ((xsread = IO->xpr_sread) == NULL)
  756.     return (0L);
  757.     if ((xchkabort = IO->xpr_chkabort) == NULL)
  758.     return (0L);
  759.     if ((xfnext = IO->xpr_fnext) == NULL)
  760.     return (0L);
  761.     if ((xffirst = IO->xpr_ffirst) == NULL)
  762.     return (0L);
  763.     if ((xsflush = IO->xpr_sflush) == NULL)
  764.     return (0L);
  765.     if ((xfwrite = IO->xpr_fwrite) == NULL)
  766.     return (0L);
  767.     if ((xgets = IO->xpr_gets) == NULL)
  768.     return (0L);
  769.     /*
  770.      * Here are callbacks we can do without.
  771.      */
  772.     xchkmisc = IO->xpr_chkmisc;
  773.     if (IO->xpr_extension >= 2)
  774.     xunlink = IO->xpr_unlink;
  775.     else
  776.     xunlink = NULL;
  777.     if (IO->xpr_extension >= 3)
  778.         xsquery = IO->xpr_squery;
  779.     else
  780.     xsquery = NULL;
  781.     xfinfo = IO->xpr_finfo;
  782.  
  783.     parity = Current->ParityFlag = XPRParity(IO);
  784.     text = Current->TextFlag;
  785.     convert = Current->ConvertFlag;
  786.     urpsiz = Current->MaxPacket;
  787.     bctr = Current->BlockCheckType;
  788.     limit = Current->RetryLimit;
  789.     rtimo = Current->Timeout;
  790.     getfile = Current->GetFlag;
  791.     keep = Current->KeepFlag;
  792.     return Current;
  793. }
  794.  
  795. /*
  796.  * Set the current context's data segment (small model) to the value
  797.  * in DataSeg.  Uses (undocumented) feature of compiler which allows
  798.  * access to variables by name between #asm ... #endasm if preceded
  799.  * by double percent sign.
  800.  */
  801. void
  802. NewDataSeg(void *DataSeg) {
  803. #ifndef _lint
  804.  
  805.     ;
  806. #asm
  807.     movea.l    %%DataSeg,a4
  808.     add.l    #32766,a4
  809. #endasm
  810.  
  811. #endif
  812. }
  813.  
  814. /*
  815.  * Have the comm program display an error message for us, using a temporary
  816.  * XPR_UPDATE structure; used to display errors before Vars gets allocated
  817.  */
  818. void
  819. ioerr(IO, msg)
  820.     struct XPR_IO  *IO;
  821.     char           *msg;
  822. {
  823.     struct XPR_UPDATE xpru;
  824.  
  825.     if ((xupdate = IO->xpr_update) != NULL) {
  826.     xpru.xpru_updatemask = XPRU_ERRORMSG;
  827.     xpru.xpru_errormsg = msg;
  828.     (void) calla(xupdate, &xpru);
  829.     }
  830. }
  831.  
  832. /*
  833.  * Simple, re-entrant versions of malloc() and free to replace the ones in
  834.  * the Aztec C libraries.  The only reason to use these instead of AllocMem()
  835.  * is that these remember the size of the stuff allocated, and we don't
  836.  * have to rewrite the system-independent Kermit code in terms of AllocMem().
  837.  */
  838.  
  839. void *malloc(size_t n)
  840. {
  841.     long *p;
  842.  
  843.     if ((p = AllocMem((long)(n + sizeof(size_t)), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  844.     return NULL;
  845.     p[0] = (long)(n + sizeof(size_t));
  846.     return (&p[1]);
  847. }
  848.  
  849. void free(void *p)
  850. {
  851.     long *s = p;
  852.  
  853.     FreeMem(&s[-1], s[-1]);
  854. }
  855.  
  856. /**
  857. *
  858. *   The following functions setup the proper registers for the call-back
  859. *   functions.
  860. *
  861. **/
  862.  
  863. #ifndef _lint
  864.  
  865. #asm
  866.         public _callad
  867. _callad:
  868.         movea.l 8(sp),a0                ; Second argument goes in a0
  869.         move.l  12(sp),d0               ; Third  argument goes in d0
  870. /*
  871. *   Now this is a trick to avoid using another register.
  872. *   Charlie taught me this...
  873. */
  874.         move.l  4(sp),-(sp)             ; First  argument is function
  875.         rts
  876.  
  877.         public  _calladda
  878. _calladda:
  879.         movea.l 8(sp),a0                ; Second argument goes in a0
  880.         move.l  12(sp),d0               ; Third  argument goes in d0
  881.         move.l  16(sp),d1               ; Fourth argument goes in d1
  882.         movea.l 20(sp),a1               ; Fifth  argument goes in a1
  883.         move.l  4(sp),-(sp)             ; First  argument is function
  884.         rts
  885.  
  886.         public  _calldaa
  887. _calldaa:
  888.         move.l  8(sp),d0                ; Second  argument goes in d0
  889.         movea.l 12(sp),a0               ; Third argument goes in a0
  890.         movea.l 16(sp),a1               ; Fourth argument goes in a1
  891.         move.l  4(sp),-(sp)             ; First  argument is function
  892.         rts
  893.  
  894.         public  _calla
  895. _calla:
  896.         movea.l 8(sp),a0                ; Second argument goes in a0
  897.         move.l  4(sp),-(sp)             ; First  argument is function
  898.         rts
  899.  
  900.         public  _calld
  901. _calld:
  902.         move.l  8(sp),d0                ; Second argument goes in d0
  903.         move.l  4(sp),-(sp)             ; First  argument is function
  904.         rts
  905.  
  906.         public  _callaa
  907. _callaa:
  908.         movea.l 8(sp),a0                ; Second argument goes in a0
  909.         movea.l 12(sp),a1               ; Third  argument goes in a1
  910.         move.l  4(sp),-(sp)             ; First  argument is function
  911.         rts
  912.  
  913.         public  _callda
  914. _callda:
  915.         move.l  8(sp),d0                ; Second argument goes in d0
  916.         movea.l 12(sp),a0               ; Third  argument goes in a0
  917.         move.l  4(sp),-(sp)             ; First  argument is function
  918.         rts
  919.  
  920.         public  _calladd
  921. _calladd:
  922.         movea.l  8(sp),a0               ; Second argument goes in a0
  923.         move.l  12(sp),d0               ; Third  argument goes in d0
  924.         move.l  16(sp),d1               ; Fourth argument goes in d1
  925.         move.l  4(sp),-(sp)             ; First  argument is function
  926.         rts
  927.  
  928. #endasm
  929. /*
  930. *   Could have added any other functions needed for other call-backs.
  931. *   Could have written a fancier single one... Could've...
  932. */
  933. #endif
  934.